package com.ziiwee.reduce.describe.creators.handlers;

import com.ziiwee.reduce.describe.AbstractDescribe;
import com.ziiwee.reduce.describe.FieldDescribe;
import com.ziiwee.reduce.describe.HandlerDescribe;
import com.ziiwee.reduce.describe.HttpRequestParameterType;
import com.ziiwee.reduce.describe.creators.HandlerDescribeCreator;
import com.ziiwee.reduce.describe.creators.fields.ParameterFieldDescribeCreator;
import com.ziiwee.reduce.describe.models.HandlerDescribeModel;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

public abstract class AbstractHandlerDescribeCreator extends AbstractDescribe implements HandlerDescribeCreator, HandlerDescribe {
    @Override
    public HandlerDescribe create() {
        return new HandlerDescribeModel(getName(), getType(), getLabel(), getDescription(), getMethods(), getPatterns(), getParameters(), getId());
    }

    @Override
    public String getId() {
        return UUID.randomUUID().toString();
    }

    protected Map<HttpRequestParameterType, List<FieldDescribe>> getParameters(Method method) {
        Parameter[] parameters = method.getParameters();
        List<FieldDescribe> path = new ArrayList<>();
        List<FieldDescribe> body = new ArrayList<>();
        List<FieldDescribe> form = new ArrayList<>();
        List<FieldDescribe> query = new ArrayList<>();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            String fieldName = parameter.getName();
            PathVariable[] pathVariable = parameter.getAnnotationsByType(PathVariable.class);
            if (pathVariable.length > 0) {
                fieldName = StringUtils.hasLength(pathVariable[0].name()) ? pathVariable[0].name() : fieldName;
                path.add(new ParameterFieldDescribeCreator(method, i, fieldName).create());
                continue;
            }
            FieldDescribe property = new ParameterFieldDescribeCreator(method, i, fieldName).create();
            RequestBody[] requestBodies = parameter.getAnnotationsByType(RequestBody.class);
            if (requestBodies.length > 0) {
                body.add(property);
                continue;
            }
            if (getMethods().contains(RequestMethod.GET.name())) {
                query.add(property);
            } else {
                form.add(property);
            }
        }
        Map<HttpRequestParameterType, List<FieldDescribe>> map = new HashMap<>();
        map.put(HttpRequestParameterType.PATH, path);
        map.put(HttpRequestParameterType.QUERY, query);
        map.put(HttpRequestParameterType.BODY, body);
        map.put(HttpRequestParameterType.FORM, form);
        return map;
    }

}
